﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.ML;
using Emgu.CV.Structure;
using MatrixLibrary;
using DotNetMatrix;


namespace finProj.Entities
{
    class minimizationMatrix
    {
        private double[,] AMatrix;
        private double[,] MMatrix;
        private double[,] MOldMatrix;
        private double[,] SMatrix;

        private void DoAMatrixnew()
        {


            IntPtr[] vectors = new IntPtr[Settings.Instance.picManager.Pictures.Count];
            Matrix<float> covar = new Matrix<float>(Settings.Instance.existingKeys.Count, Settings.Instance.existingKeys.Count);
            Matrix<float> sample;
            this.AMatrix = new double[Settings.Instance.existingKeys.Count, Settings.Instance.existingKeys.Count];
            for (int i = 0; i < Settings.Instance.picManager.Pictures.Count; i++)
            {
                sample = new Matrix<float>(Settings.Instance.existingKeys.Count, 1);
                for (int j = 0; j < Settings.Instance.existingKeys.Count; j++)
                {
                    sample[j, 0] = (float)
                        Settings.Instance.picManager.Pictures[i].FeaturesVec.features[Settings.Instance.existingKeys[j]];

                }
                vectors[i] = sample;
            }
            CvInvoke.cvCalcCovarMatrix(vectors, Settings.Instance.picManager.Pictures.Count, covar, IntPtr.Zero, COVAR_METHOD.CV_COVAR_NORMAL);
            for (int i = 0; i < Settings.Instance.existingKeys.Count; i++)
            {
                for (int j = 0; j < Settings.Instance.existingKeys.Count; j++)
                {
                    AMatrix[i, j] = covar[i, j];
                }
            }


        }

        private void DoSMatrix()
        {
            this.SMatrix = new double[Settings.Instance.existingKeys.Count, Settings.Instance.existingKeys.Count];
            double[,] inverse = new double[Settings.Instance.existingKeys.Count, Settings.Instance.existingKeys.Count];
            inverse = InversMatrix(AMatrix);
            double det = determinant(AMatrix);
            this.SMatrix = Matrix.ScalarMultiply(det, inverse);

        }

        private void DoMMatrix()
        {
            this.MMatrix = new double[Settings.Instance.existingKeys.Count, Settings.Instance.existingKeys.Count];
            double[,] sqrtL = new double[Settings.Instance.existingKeys.Count, Settings.Instance.existingKeys.Count];
            double[,] vec = new double[Settings.Instance.existingKeys.Count, Settings.Instance.existingKeys.Count];
            double[,] Tvec = new double[Settings.Instance.existingKeys.Count, Settings.Instance.existingKeys.Count];
            double[,] val = new double[Settings.Instance.existingKeys.Count, 1];
            Matrix.Eigen(SMatrix, out val, out vec);
            Tvec = Matrix.Transpose(vec);
            for (int i = 0; i < Settings.Instance.existingKeys.Count; i++)
            {
                for (int j = 0; j < Settings.Instance.existingKeys.Count; j++)
                {
                    if (i == j)
                    {
                        sqrtL[i, j] = Math.Sqrt(Math.Abs(val[i, 0]));
                    }
                    else { sqrtL[i, j] = 0; }
                }
            }
            this.MMatrix = Matrix.Multiply((Matrix.Multiply(vec, sqrtL)), Tvec);


        }

        private double determinant(Double[,] matrix)
        {
            double det ;
            double pow;
            det = Matrix.Det(matrix);
            det = Math.Abs(det);
            pow = Settings.Instance.existingKeys.Count;
            det = Math.Pow(det, (double) (1/pow));
            return (det);
        }

        private double[,] InversMatrix(Double[,] matrix)
        {
            double[,] mat = new double[Settings.Instance.existingKeys.Count, Settings.Instance.existingKeys.Count];
            double det;
            det = Matrix.Det(matrix);
            if (det == 0)
            {
                mat = Matrix.PINV(matrix);
            }
            else
            {
                mat = Matrix.Inverse(matrix);
            }

            return (mat);
        }
        private int check(double[,] m)
        {
            int flag = 1;
            double[] temp = new double[Settings.Instance.existingKeys.Count];


            for (int i = 0; i < Settings.Instance.picManager.Pictures.Count; i++)
            {
                for (int j = 0; j < Settings.Instance.existingKeys.Count; j++)
                {

                    temp[j] =
                       Settings.Instance.picManager.Pictures[i].FeaturesVec.features[Settings.Instance.existingKeys[j]];




                }
                if (Matrix.IsEqual((Matrix.OneD_2_TwoD(temp)), (Matrix.Multiply((m), (Matrix.OneD_2_TwoD(temp))))) == false)
                {
                    flag = 0;
                }
            }

            return (flag);
        }
        public double[,] DoMinimizationMatrix()
        {
            double[] temp = new double[Settings.Instance.existingKeys.Count];
            double[,] zero = new double[Settings.Instance.existingKeys.Count, Settings.Instance.existingKeys.Count];
            this.MOldMatrix =new double[Settings.Instance.existingKeys.Count,Settings.Instance.existingKeys.Count];
            DoAMatrix();
            if (Matrix.IsEqual((AMatrix), (zero)) == true)
                return (zero);
            DoSMatrix();
            DoMMatrix();
            int Iterator = 0;
            while ((check(this.MMatrix) <= 0) && (Iterator != 10000))
            {
                for (int i = 0; i < Settings.Instance.picManager.Pictures.Count; i++)
                {
                    for (int j = 0; j < Settings.Instance.existingKeys.Count; j++)
                    {

                        temp[j] = Settings.Instance.picManager.Pictures[i].FeaturesVec.features[Settings.Instance.existingKeys[j]];

                    }
                    temp = Matrix.TwoD_2_OneD(Matrix.Multiply((this.MMatrix), (Matrix.OneD_2_TwoD(temp))));
                    int k = Settings.Instance.picManager.Pictures[i].FeaturesVec.Change_featurevectors_keys(temp);
                }
                for (int k = 0; k < Settings.Instance.clusterManager.clusters.Count();k++ )
                {
                    double[] tempCentroid = new double[Settings.Instance.existingKeys.Count()];
                    for (int l = 0; l < Settings.Instance.existingKeys.Count(); l++)
                    {
                        tempCentroid[l] = (double) Settings.Instance.clusterManager.clusters[k].centroid[l];
                    }
                    tempCentroid =
                        Matrix.TwoD_2_OneD(Matrix.Multiply((this.MMatrix), (Matrix.OneD_2_TwoD(tempCentroid))));
                    for (int l = 0; l < Settings.Instance.existingKeys.Count(); l++)
                    {
                        Settings.Instance.clusterManager.clusters[k].centroid[l] = (float)tempCentroid[l];
                    }
                }
                for (int i = 0; i < Settings.Instance.existingKeys.Count();i++ )
                {
                    for(int j=0;j<Settings.Instance.existingKeys.Count();j++)
                    {
                        this.MOldMatrix[i,j] = this.MMatrix[i,j];
                    }
                }
                    DoAMatrix();
                DoSMatrix();
                DoMMatrix();
                Iterator++;
            }

            double det = Matrix.Det(MMatrix);

            if(double.IsNaN(det))
            {
                return (MOldMatrix);
            }

            return (MMatrix);
        }
        private void DoAMatrix()
        {

            double firstPart = 0.0;
            double secondPart = 0.0;
            double eq, eq1, eq2;
            int l;
            int k;
            this.AMatrix = new double[Settings.Instance.existingKeys.Count, Settings.Instance.existingKeys.Count];
            for (int m = 0; m < Settings.Instance.existingKeys.Count; m++)
            {
                for (int n = 0; n < Settings.Instance.existingKeys.Count; n++)
                {
                    this.AMatrix[m, n] = 0;
                }
            }

            for (k = 0; k < Settings.Instance.existingKeys.Count; k++)
            {
                for (l = 0; l < Settings.Instance.existingKeys.Count; l++)
                {
                    eq2 = 0;
                    for (int i = 0; i < Settings.Instance.numberOfPeople; i++)
                    {
                        eq1 = 0;

                        for (int j = 0; j < Settings.Instance.clusterManager.clusters[i].pictures.Count; j++)//skol'ko vektorov v klastere
                        {
                            if (Settings.Instance.clusterManager.clusters[i].pictures[j].FeaturesVec.GetSize() == Settings.Instance.existingKeys.Count)
                            {
                                firstPart =
                                    ((Settings.Instance.clusterManager.clusters[i].pictures[j].FeaturesVec.
                                         Get_only_key_from_featuresavector()[l]) -
                                     (Settings.Instance.clusterManager.clusters[i].centroid[l]));
                                secondPart =
                                    ((Settings.Instance.clusterManager.clusters[i].pictures[j].FeaturesVec.
                                         Get_only_key_from_featuresavector()[k]) -
                                     (Settings.Instance.clusterManager.clusters[i].centroid[k]));
                            }
                            eq = firstPart * secondPart;
                            eq1 = eq1 + eq;
                        }
                        eq2 = eq2 + eq1;
                    }
                    this.AMatrix[k, l] = eq2;

                }
            }

        }



    }
}
